using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace App
{
    public partial class Btn : Control
    {

        private System.ComponentModel.IContainer components = null;
        private System.Windows.Forms.Timer flashTimer;

        public event EventHandler<ButtonConfirmedEventArgs> Confirmed;
        public class ButtonConfirmedEventArgs : EventArgs
        {
            public ButtonConfirmedEventArgs(MouseEventArgs e) { }
        }

        public event EventHandler<ButtonClickedEventArgs> Clicked;

        public class ButtonClickedEventArgs : EventArgs
        {
            public ButtonClickedEventArgs(MouseEventArgs e) { }
        }

        public event EventHandler<ButtonCheckedEventArgs> Checked;

        public class ButtonCheckedEventArgs : EventArgs
        {
            public ButtonCheckedEventArgs(Boolean buttonChecked, MouseEventArgs e) { }
        }

        protected internal Color INTERNAL_ORIGINAL_BACKGROUNDCOLOR { get; set; }

        private Boolean
            mouseDown,
            mouseEntered,
            checkForMouseActions;

        // [EXPERIMENTAL: NEW SYNTAX]
        protected internal Boolean INTERNAL_BUTTON_CHECKFOR_CLICKEDINSIDECHECKBOX { get; set; }
        protected internal Boolean INTERNAL_BUTTON_SHOULDFLASH { get; set; }
        protected internal Boolean INTERNAL_BUTTON_CONFIRMATION_SETINSTONE { get; set; }

        protected internal Int32 INTERNAL_FLASHINGBUTTONTIMER_TIMESTOFLASH { get; set; }
        protected internal Int32 INTERNAL_BUTTONFLASHTIMER_TICKCOUNT { get; set; }
        protected internal Int32 INTERNAL_BUTTONFLASHTIMER_INTERVAL { get; set; }

        protected internal DateTime
            startFlashingTime,
            endFlashingTime;
        protected internal DateTime[]
            changeFlashingTimes;

        Graphics graphics;

        [EditorBrowsable(EditorBrowsableState.Always),
            Category("Behavior"),
            Description(
            "Determines whether this button requires confirmation from the user."
            )
        ]
        public Boolean
            ConfirmationRequired
        { get; set; }

        [EditorBrowsable(EditorBrowsableState.Always), Category("Behavior"), Description("Determines whether the user has confirmed or agreed.")]
        protected internal Boolean
            ButtonConfirmed
        { get; set; }

        [EditorBrowsable(EditorBrowsableState.Always), Category("Appearance"), Description("The highlight color of the component, which is displayed when the user moves the cursor within the bounds of the control.")]
        public Color HighlightColor { get { return m_HighlightColor; } set { m_HighlightColor = value; } }
        private Color m_HighlightColor = Color.FromArgb(201, 224, 235);

        [EditorBrowsable(EditorBrowsableState.Always), Category("Appearance"), Description("The active color of the component when it is being clicked.")]
        public Color ActiveColor { get { return m_ActiveColor; } set { m_ActiveColor = value; } }
        private Color m_ActiveColor = Color.FromArgb(191, 214, 225);

        [EditorBrowsable(EditorBrowsableState.Always), Category("Appearance"), Description("The border color of the component.")]
        public Color BorderColor { get { return m_BorderColor; } set { m_BorderColor = value; } }
        private Color m_BorderColor = Color.FromArgb(106, 185, 232);

        [EditorBrowsable(EditorBrowsableState.Always), Category("Appearance"), Description("The thickness of the component's borders.")]
        public Int32 BorderThickness { get; set; }

        [EditorBrowsable(EditorBrowsableState.Always), Category("Appearance"), Description("The background color of the component's checkbox when it is flashing.")]
        public Color FlashColor { get { return m_FlashColor; } set { m_FlashColor = value; } }
        private Color m_FlashColor = Color.FromArgb(234, 148, 138);

        [EditorBrowsable(EditorBrowsableState.Always), Category("Appearance"), Description("The background color of the component when its state has been set to Confirmed.")]
        public Color ConfirmedBackgroundColor { get { return m_ConfirmedBackgroundColor; } set { m_ConfirmedBackgroundColor = value; } }
        private Color m_ConfirmedBackgroundColor = Color.FromArgb(231, 248, 228);

        [EditorBrowsable(EditorBrowsableState.Always), Category("Appearance"), Description("The border color of the component when its state has been set to Confirmed.")]
        public Color ConfirmedBorderColor { get { return m_ConfirmedBorderColor; } set { m_ConfirmedBorderColor = value; } }
        private Color m_ConfirmedBorderColor = Color.FromArgb(159, 227, 142);

        public Btn()
        {
            InitializeComponent();

            this.DoubleBuffered = true;
            this.BackColor = Color.FromArgb(211, 234, 248);
            INTERNAL_ORIGINAL_BACKGROUNDCOLOR = this.BackColor;
            INTERNAL_FLASHINGBUTTONTIMER_TIMESTOFLASH = 5;
            INTERNAL_BUTTONFLASHTIMER_INTERVAL = 200;
        }

     
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }


        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.flashTimer = new System.Windows.Forms.Timer(this.components);
            this.SuspendLayout();
            // 
            // flashTimer
            // 
            this.flashTimer.Tick += new System.EventHandler(this.flashTimer_Tick);
            // 
            // Button
            // 
            this.Enter += new System.EventHandler(this.Button_Enter);
            this.Leave += new System.EventHandler(this.Button_Leave);
            this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Button_MouseClick);
            this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Button_MouseDown);
            this.MouseEnter += new System.EventHandler(this.Button_MouseEnter);
            this.MouseLeave += new System.EventHandler(this.Button_MouseLeave);
            this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.Button_MouseUp);
            this.ResumeLayout(false);

        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            int buttonWidth = this.Size.Width,
                buttonHeight = this.Size.Height;

            graphics = pe.Graphics;

            if (ConfirmationRequired)
            {
                if (ButtonConfirmed)
                {
                    // Since confirmation is required, draw a checkbox. And since the user
                    // has already ButtonConfirmed, draw the check mark, too.
                    graphics.DrawLine(new Pen(BorderColor, BorderThickness), 27, 0, 27, buttonHeight);

                    graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

                    graphics.DrawLine(new Pen(ForeColor, BorderThickness),
                        7, 15, 11, 18);

                    graphics.DrawLine(new Pen(ForeColor, BorderThickness),
                        11, 18, 18, 10);

                    TextFormatFlags flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis;
                    TextRenderer.DrawText(graphics, this.Text, this.Font, new Rectangle(27, 0, this.Width - 27, this.Height), this.ForeColor, flags);

                    if (checkForMouseActions)
                    {
                        checkForMouseActions = false;

                        if (mouseDown)
                        {
                            // It's also entered.
                            if (INTERNAL_BUTTON_CHECKFOR_CLICKEDINSIDECHECKBOX)
                            {
                                Brush brush = new SolidBrush(ActiveColor);
                                graphics.FillRectangle(brush, 1, 1, 26, this.Height - 1);

                                graphics.DrawLine(new Pen(ForeColor, BorderThickness),
                                    7, 15, 11, 18);

                                graphics.DrawLine(new Pen(ForeColor, BorderThickness),
                                    11, 18, 18, 10);

                                brush.Dispose();
                            }
                        }
                    }
                }
                else
                {
                    // Draw a checkbox but do not draw a check mark because the user has yet to confirm.
                    graphics.DrawLine(new Pen(BorderColor, BorderThickness), 27, 0, 27, buttonHeight);

                    TextFormatFlags flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis;
                    TextRenderer.DrawText(graphics, this.Text, this.Font, new Rectangle(27, 0, this.Width - 27, this.Height), this.ForeColor, flags);

                    if (checkForMouseActions)
                    {
                        checkForMouseActions = false;

                        if (mouseDown)
                        {
                            // It's also entered.
                            if (INTERNAL_BUTTON_CHECKFOR_CLICKEDINSIDECHECKBOX)
                            {
                                Brush brush = new SolidBrush(ActiveColor);

                                if (INTERNAL_BUTTON_SHOULDFLASH)
                                {
                                    Brush flashBrush = new SolidBrush(FlashColor);
                                    graphics.FillRectangle(brush, 1, 1, 26, this.Height - 1);

                                    //flashBrush.Dispose();
                                }
                                else
                                    graphics.FillRectangle(brush, 1, 1, 26, this.Height - 1);

                                brush.Dispose();
                            }
                            else
                            {
                                if (INTERNAL_BUTTON_CHECKFOR_CLICKEDINSIDECHECKBOX)
                                {
                                    Brush brush = new SolidBrush(ActiveColor);

                                    if (INTERNAL_BUTTON_SHOULDFLASH)
                                    {
                                        Brush flashBrush = new SolidBrush(FlashColor);
                                        graphics.FillRectangle(brush, 1, 1, 26, this.Height - 1);

                                        //flashBrush.Dispose();
                                    }

                                    brush.Dispose();
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                // [DEPRECATED: UNNECESSARY] Confirmed = false; // Check back here later. Probably shouldn't do this.
                // This is a Standard button. Do not draw a checkbox.

                TextFormatFlags flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis;
                TextRenderer.DrawText(graphics, this.Text, this.Font, new Rectangle(0, 0, this.Width, this.Height), this.ForeColor, flags);

                if (checkForMouseActions)
                {
                    checkForMouseActions = false;
                }
            }

            if (this.Enabled)
                graphics.DrawRectangle(new Pen(BorderColor, BorderThickness), 0, 0, buttonWidth - 1, buttonHeight - 1);
            else if (!this.Enabled && ConfirmationRequired && ButtonConfirmed)
            {
                graphics.DrawLine(new Pen(ConfirmedBorderColor, BorderThickness), 27, 0, 27, buttonHeight);

                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

                graphics.DrawLine(new Pen(ForeColor, BorderThickness),
                    7, 15, 11, 18);

                graphics.DrawLine(new Pen(ForeColor, BorderThickness),
                    11, 18, 18, 10);

                graphics.DrawRectangle(new Pen(ConfirmedBorderColor, BorderThickness), 0, 0, buttonWidth - 1, buttonHeight - 1);
            }
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            this.Refresh();
        }

        private void Button_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Location.X >= 0 && e.Location.X <= 27 && e.Location.Y >= 0 && e.Location.Y <= this.Height)
            {
                if (ButtonConfirmed)
                {
                    ButtonConfirmed = false;
                }
                else
                {
                    ButtonConfirmed = true;
                }

                this.Refresh();
            }
            else
            {
                if (ConfirmationRequired)
                {
                    if (ButtonConfirmed)
                    {
                        INTERNAL_BUTTON_CONFIRMATION_SETINSTONE = true;
                        this.Enabled = false;
                        this.BackColor = ConfirmedBackgroundColor;

                        Confirmed(this, new ButtonConfirmedEventArgs(e));

                        this.Refresh();
                    }
                }

                this.Focus();

                if (Clicked != null)
                {
                    Clicked(this, new ButtonClickedEventArgs(e));
                }
            }
        }

        private void Button_MouseEnter(object sender, EventArgs e)
        {
            checkForMouseActions = true;
            mouseEntered = true;

            INTERNAL_ORIGINAL_BACKGROUNDCOLOR = this.BackColor;
            this.BackColor = HighlightColor;

            this.Refresh();
        }

        private void Button_MouseLeave(object sender, EventArgs e)
        {
            checkForMouseActions = true;
            mouseEntered = false;

            if (!INTERNAL_BUTTON_CONFIRMATION_SETINSTONE)
                this.BackColor = INTERNAL_ORIGINAL_BACKGROUNDCOLOR;

            this.Refresh();
        }

        private void Button_Enter(object sender, EventArgs e)
        {
            this.Refresh();
        }

        private void Button_Leave(object sender, EventArgs e)
        {
            this.Refresh();
        }

        private void flashTimer_Tick(object sender, EventArgs e)
        {
            if (changeFlashingTimes.Contains(DateTime.Now))
            {
                this.Refresh();
            }
        }

        private void Button_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Location.X >= 0 && e.Location.X <= 27 && e.Location.Y >= 0 && e.Location.Y <= this.Height)
            {
                INTERNAL_BUTTON_CHECKFOR_CLICKEDINSIDECHECKBOX = true;
            }
            else
            {
                INTERNAL_BUTTON_CHECKFOR_CLICKEDINSIDECHECKBOX = false;
                this.BackColor = ActiveColor;
            }

            checkForMouseActions = true;
            mouseDown = true;

            this.Focus();

            this.Refresh();
        }

        private void Button_MouseUp(object sender, MouseEventArgs e)
        {
            checkForMouseActions = true;
            mouseDown = false;

            if (ConfirmationRequired && ButtonConfirmed)
            {
                if (e.Location.X >= 28 && e.Location.X <= this.Width && e.Location.Y >= 0 && e.Location.Y <= this.Height)
                {
                    this.BackColor = ConfirmedBackgroundColor;
                    this.Enabled = false;
                }
            }
            else
            {
                this.BackColor = HighlightColor;
                if (!this.Enabled) this.Enabled = true;
            }

            this.Refresh();
        }
    }
}
